{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Gradient-based optimization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If information about the gradient is available, it can accelarate convergence substantially." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Newton's optimization method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Newton's optimization routine aims to find the root of the gradient, which is the extremal. Since we are now focussed on scalar $f(\\vec{x})$ the gradient is a vector and we will need the Hessian matrix $$H = \\frac{\\partial^2 f}{{\\partial \\vec{x}}^2}$$\n", "\n", "The increment is now solved as:\n", "\n", "$$\n", "H \\Delta \\vec{x} = - \\nabla f\n", "$$\n", "\n", "Noting that $H$ must be symmetric." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Netwon's optimization method has excellent convergence criteria but requires calculation of the Hessian which can be computationally expensive." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from scipy.linalg import solve\n", "import plotly.graph_objects as go\n", "\n", "def newton_method(f, grad_f, hessian_f, x0, tol=1e-6, max_iter=100):\n", " x = x0\n", " print(x)\n", " guesses = [x]\n", " for _ in range(max_iter):\n", " grad = grad_f(x)\n", " hess = hessian_f(x)\n", "\n", " # ~~ What goes here?\n", "\n", " ###\n", " delta_x = solve(hess, -grad, assume_a = 'sym')\n", " ###\n", " x = x + delta_x\n", " guesses.append(x)\n", " print(x)\n", " if np.linalg.norm(grad) < tol:\n", " break\n", "\n", " # Create a surface plot of the function\n", " x = np.linspace(-2, 2, 100)\n", " y = np.linspace(-2, 2, 100)\n", " X, Y = np.meshgrid(x, y)\n", " Z = f([X, Y])\n", "\n", " fig = go.Figure(data=[go.Surface(x=X, y=Y, z=Z)])\n", "\n", " # Add markers for each guess\n", " for guess in guesses:\n", " fig.add_trace(go.Scatter3d(\n", " x=[guess[0]],\n", " y=[guess[1]],\n", " z=[f(guess)],\n", " mode='markers',\n", " marker=dict(\n", " size=5,\n", " color='red'\n", " )\n", " ))\n", "\n", " fig.update_layout(\n", " title='Newton\\'s Method Optimization',\n", " scene=dict(\n", " xaxis_title='x',\n", " yaxis_title='y',\n", " zaxis_title='f(x,y)'\n", " )\n", " )\n", " fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example: Minimize $x^4 + y^4$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1.5 2. ]\n", "[1. 1.33333333]\n", "[0.66666667 0.88888889]\n", "[0.44444444 0.59259259]\n", "[0.2962963 0.39506173]\n", "[0.19753086 0.26337449]\n", "[0.13168724 0.17558299]\n", "[0.0877915 0.11705533]\n", "[0.05852766 0.07803688]\n", "[0.03901844 0.05202459]\n", "[0.02601229 0.03468306]\n", "[0.01734153 0.02312204]\n", "[0.01156102 0.01541469]\n", "[0.00770735 0.01027646]\n", "[0.00513823 0.00685097]\n", "[0.00342549 0.00456732]\n", "[0.00228366 0.00304488]\n" ] }, { "data": { "text/html": [ "\n", "
\n", "\n", "